package com.jiutianniao.p2p.acctrans.core.account.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jiutianniao.p2p.acctrans.core.account.Account;
import com.jiutianniao.p2p.acctrans.core.dal.model.AccountDO;
import com.jiutianniao.p2p.acctrans.core.dal.model.AccountFreezeLogDO;
import com.jiutianniao.p2p.acctrans.core.dal.model.AccountLogDO;
import com.jiutianniao.p2p.acctrans.core.exception.TransException;
import com.jiutianniao.p2p.acctrans.core.service.ServiceBeans;
import com.jiutianniao.p2p.base.model.Money;
import com.jiutianniao.p2p.trans.client.enums.AccountActionEnum;
import com.jiutianniao.p2p.trans.client.enums.FreezeBalanceTypeEnum;
import com.jiutianniao.p2p.trans.client.enums.RecordModelEnum;
import com.jiutianniao.p2p.trans.client.enums.TransResultEnum;
import com.jiutianniao.p2p.trans.client.model.TransInfo;

/**
 * 标准账户的账务包装
 *
 */
public class StandardAccount implements Account {

	private final Logger logger = LoggerFactory
			.getLogger(StandardAccount.class);

	private ServiceBeans serviceBeans;

	/** 动作 */
	protected AccountActionEnum action;

	/** 交易对方账户 */
	private Account otherAccount;
	/** 账户DO */
	private AccountDO accountDO;

	public StandardAccount() {

	}

	@Override
	public void debit(Money transAmount, TransInfo transInfo)
			throws TransException {
		if (action == AccountActionEnum.DEBIT
				|| action == AccountActionEnum.WITHDRAW) {

			// 2. 更新余额
			updateBalance(transAmount, transInfo);

			// 3. 记录记账凭证
			Money newBalance = getAccountDO().getBalance();
			AccountLogDO accountLogDO = recordAccountLog(transAmount,
					newBalance, transInfo);
			this.getServiceBeans().getAccountLogService().saveLog(accountLogDO);

		} else {
			logger.warn("账户操作类型不正确。[AccountActionEnum=" + action + "]");
			throw new TransException(TransResultEnum.account_action_type_error);
		}

	}

	@Override
	public void credit(Money transAmount, TransInfo transInfo)
			throws TransException {
		if (action == AccountActionEnum.CREDIT
				|| action == AccountActionEnum.DEPOSIT) {
			// 1. 更新余额
			updateBalance(transAmount, transInfo);

			// 2. 记录记账凭证
			Money newBalance = getAccountDO().getBalance();
			AccountLogDO accountLogDO = recordAccountLog(transAmount,
					newBalance, transInfo);
			this.getServiceBeans().getAccountLogService().saveLog(accountLogDO);
			/*
			 * // // 3. 记变动账信息 // this.recordDailyChange(transAmount, transInfo,
			 * transInfo.getTransCode(), false); recordDailyChange(transAmount,
			 * transInfo, transInfo.getTransCode(), false);
			 * 
			 * // 4. 添加通知会计核心任务 addAccoreTask(accountLogDO, transAmount,
			 * newBalance, transInfo, accoreTask, subTransCodeConfig, null);
			 */
		} else {
			logger.warn("账户操作类型不正确。[AccountActionEnum=" + action + "]");
			throw new TransException(TransResultEnum.account_action_type_error);
		}

	}

	@Override
	public Long freeze(Money freezeAmount, FreezeBalanceTypeEnum freezeType,
			TransInfo transInfo) throws TransException {
		// 累计
		getAccountDO().getFreezeAmount().add(freezeAmount);

		if (getAccountDO().getBalance().getCent()-getAccountDO().getFreezeAmount().getCent() < 0) {
			throw new TransException(TransResultEnum.balance_not_enough_error);
		}
		this.serviceBeans.getAccountService().updateForBalanceAndFreezeAmount(
				getAccountDO());

		/*
		 * // 增加账户该冻结类型余额 AccountFreezeDO accountFreezeDO =
		 * daoBean.getAccountFreezeDAO()
		 * .getByAccountNoAndFreezeType(getAccountNo(),
		 * freezeType.getValue().toString());
		 * 
		 * Money newTypeFreeze = null; if (accountFreezeDO == null) {
		 * newTypeFreeze = freezeAmount; accountFreezeDO = new
		 * AccountFreezeDO(); accountFreezeDO.setIwAccountNo(getAccountNo());
		 * accountFreezeDO.setFreezeType(freezeType.getValue().toString());
		 * accountFreezeDO.setFreezeAmount(newTypeFreeze);
		 * daoBean.getAccountFreezeDAO().insert(accountFreezeDO); } else { Money
		 * oldTypeFreeze = accountFreezeDO.getFreezeAmount(); newTypeFreeze =
		 * oldTypeFreeze.add(freezeAmount);
		 * daoBean.getAccountFreezeDAO().updateFreezeAmount(newTypeFreeze,
		 * transInfo.getTransDt(), accountFreezeDO.getId()); }
		 */
		/*
		 * // 事后复查 this.checkBalance();
		 */

		// 记冻结日志
		return recordFreezeLog(freezeAmount, getAccountDO().getFreezeAmount(),
				freezeType, transInfo, true);

	}

	@Override
	public Long unFreeze(Money unFreezeAmount,
			FreezeBalanceTypeEnum freezeType, TransInfo transInfo)
			throws TransException {

		getAccountDO().getFreezeAmount().sub(unFreezeAmount);
		if (getAccountDO().getFreezeAmount().getCent() < 0) {
			throw new TransException(TransResultEnum.balance_not_enough_error);
		}

		this.serviceBeans.getAccountService().updateForBalanceAndFreezeAmount(
				getAccountDO());
		// 记冻结日志
		return recordFreezeLog(unFreezeAmount,
				getAccountDO().getFreezeAmount(), freezeType, transInfo, false);
	}

	@Override
	public String getAccountNo() {
		return this.accountDO.getAccountNo();
	}

	@Override
	public int getAccountType() {
		if (this.accountDO.getAccountType() == null) {
			return 1;
		} else {
			return this.accountDO.getAccountType();
		}
	}

	@Override
	public Account getOtherAccount() {
		return otherAccount;
	}

	@Override
	public void setOtherAccount(Account otherAccount) {
		this.otherAccount = otherAccount;
	}

	@Override
	public String getAccountTitle() {
		return this.accountDO.getAccountTitle();
	}

	@Override
	public RecordModelEnum getRecordModel() {
		return null;
	}

	@Override
	public boolean isAsset() throws TransException {
		String accountTitle = getAccountDO().getAccountTitle();

		if (accountTitle.startsWith("1")) {
			// 1.资产
			return true;
		} else if (accountTitle.startsWith("2")) {
			// 2.负债
			return false;
		} /*
		 * else if (accountTitle.startsWith("3")) { // 3.所有权 return true; }
		 */else {
			logger.warn("不存在的科目类别。[AccountTitle=" + accountTitle + "]");
			throw new TransException(TransResultEnum.subjects_not_exist);
		}
	}

	@Override
	public boolean isAdd() throws TransException {
		if (action == AccountActionEnum.CREDIT
				|| action == AccountActionEnum.DEPOSIT
				|| action == AccountActionEnum.DEBIT
				|| action == AccountActionEnum.WITHDRAW) {
			boolean isDebit = action == AccountActionEnum.DEBIT
					|| action == AccountActionEnum.WITHDRAW;
			return !(isDebit ^ isAsset());
		} else if (action == AccountActionEnum.FREEZE) {
			return false;
		} else if (action == AccountActionEnum.UN_FREEZE) {
			return true;
		} else {
			logger.warn("不支持的账户操作。");
			throw new TransException(
					TransResultEnum.account_action_type_not_support);
		}
	}

	private void updateBalance(Money money, TransInfo transInfo)
			throws TransException {
		long canUseBalance = getAccountDO().getBalance().getCent()
				- getAccountDO().getFreezeAmount().getCent();

		if (action == AccountActionEnum.ACCOUNT_LOG) {
			// 基于记账凭证的操作
			if (logger.isDebugEnabled()) {
				logger.debug("基于记账凭证的余额更新。[Money=" + money + ", TransInfo="
						+ transInfo + "]");
			}
			getAccountDO().getBalance().add(money);
		} else if (isAdd()) {
			// 增加余额
			if (logger.isDebugEnabled()) {
				logger.debug("增加余额。[Money=" + money + ", TransInfo="
						+ transInfo + "]");
			}

			getAccountDO().getBalance().add(money);
		} else {
			// 减少余额
			if (logger.isDebugEnabled()) {
				logger.debug("减少余额。[Money=" + money + ", TransInfo="
						+ transInfo + "]");
			}
			if (canUseBalance < money.getCent()) {
				throw new TransException(
						TransResultEnum.balance_not_enough_error);
			}
			getAccountDO().getBalance().sub(money);
		}

		this.getServiceBeans().getAccountService()
				.updateForBalanceAndFreezeAmount(getAccountDO());
	}

	/**
	 * 记录记账凭证
	 * 
	 * @param transAmount
	 *            交易金额
	 * @param balance
	 *            这比交易后的帐户余额
	 * @param transInfo
	 *            交易信息
	 * @param long 记账凭证号
	 * @throws TransException
	 */
	protected AccountLogDO recordAccountLog(Money transAmount, Money balance,
			TransInfo transInfo) throws TransException {

		Long transLogId = transInfo.getTransLogId();
		int transCodeInt = transInfo.getTransCode().getCode();
		String transCode = String.valueOf(transCodeInt);
		// String subTransCode =
		// transInfo.getSubTransCode().getValue().toString();

		// 计算交易金额
		Money amount = transAmount.createNewAmount();
		if (!isAdd()) {
			amount.multiplyBy(-1);

		}

		// 根据借货性质，生成记账凭证号,取得备注信息
		long accountLogId = 0;
		String memo = null;
		if (action == AccountActionEnum.DEBIT
				|| action == AccountActionEnum.WITHDRAW) {
			accountLogId = transLogId * 10;
			memo = transInfo.getTransMemo();
		} else if (action == AccountActionEnum.CREDIT
				|| action == AccountActionEnum.DEPOSIT) {
			accountLogId = transLogId * 10 + 1;
			memo = transInfo.getTransMemo();
		} else {
			logger.warn("不支持的账户操作。[AccountActionEnum=" + action + "]");
			throw new TransException(TransResultEnum.account_action_type_error);
		}

		AccountLogDO accountLogDO = new AccountLogDO();
		accountLogDO.setAccountType(getAccountType());
		accountLogDO.setBalance(balance);
		accountLogDO.setTransAccount(getAccountNo());
		accountLogDO.setTransAmount(amount);
		accountLogDO.setAccountLogId(accountLogId);
		accountLogDO.setTransMemo(memo);
		accountLogDO.setTransCode(transCode); // 交易代码
		if (transInfo.getSubTransCode() != null) {
			accountLogDO.setSubTransCode(transInfo.getSubTransCode().getCode());
		}
		accountLogDO.setTransCurrency("156");
		accountLogDO.setTransDate(transInfo.getTransDate());
		accountLogDO.setTransDt(transInfo.getTransDt());
		accountLogDO.setOutDate(transInfo.getOutDate());
		accountLogDO.setTransInstitution("");
		accountLogDO.setTransLogId(transLogId);
		accountLogDO.setTransOutOrderNo(transInfo.getTransOutOrderNo());
		accountLogDO.setOtherAccount(getOtherAccount().getAccountNo());
		accountLogDO.setOtherAccountType(getOtherAccount().getAccountType());
		// accountLogDO.setBankName(bankName);
		accountLogDO.setOutBizNo(transInfo.getTransOutBizNo());
		// accountLogDO.setSuiteId("");
		accountLogDO.setVoucherId(transInfo.getVoucherId());
		// accountLogDO.setOrgiVoucherId("");
		accountLogDO.setTransOperator(transInfo.getTransOperator());
		// accountLogDO.setInstChannelApi("");

		return accountLogDO;
	}

	private Long recordFreezeLog(Money acount, Money totalFreeze,
			FreezeBalanceTypeEnum freezeType, TransInfo transInfo,
			boolean isFreeze) {
		// -- 记录冻结明细（日志）--
		AccountFreezeLogDO accountFreezeLogDO = new AccountFreezeLogDO();
		accountFreezeLogDO.setAccountNo(getAccountNo());
		accountFreezeLogDO.setOutOrderNo(transInfo.getTransOutOrderNo());
		accountFreezeLogDO.setActionType(isFreeze ? "F" : "U");
		accountFreezeLogDO.setAmount(acount);
		accountFreezeLogDO.setFreezeType(String.valueOf(freezeType.getCode()));
		accountFreezeLogDO.setTotalFreezeAmount(totalFreeze);
		accountFreezeLogDO.setOperator(transInfo.getTransOperator());
		accountFreezeLogDO.setGmtCreate(transInfo.getTransDt());

		return this.serviceBeans.getAccountFreezeLogService().saveFreezeLog(
				accountFreezeLogDO);
	}

	public ServiceBeans getServiceBeans() {
		return serviceBeans;
	}

	public void setServiceBeans(ServiceBeans serviceBeans) {
		this.serviceBeans = serviceBeans;
	}

	public AccountActionEnum getAction() {
		return action;
	}

	public void setAction(AccountActionEnum action) {
		this.action = action;
	}

	public AccountDO getAccountDO() {
		return accountDO;
	}

	public void setAccountDO(AccountDO accountDO) {
		this.accountDO = accountDO;
	}

}
